package test.administrator.example.com.mvptest1.framework.support.viewstate.fragment;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.View;

import java.util.UUID;

import test.administrator.example.com.mvptest1.framework.MvpPresenter;
import test.administrator.example.com.mvptest1.framework.MvpView;
import test.administrator.example.com.mvptest1.framework.support.fragment.FragmentMvpDelegate;
import test.administrator.example.com.mvptest1.framework.support.fragment.FragmentMvpDelegateImpl;
import test.administrator.example.com.mvptest1.framework.support.manager.PresenterManager;
import test.administrator.example.com.mvptest1.framework.support.viewstate.MvpViewStateDelegateCallback;
import test.administrator.example.com.mvptest1.framework.support.viewstate.RestorableViewState;
import test.administrator.example.com.mvptest1.framework.support.viewstate.ViewState;

/**
 * 第一重代理：生命周期->目标对象->数据缓存（ViewState）
 * 第二重代理：数据缓存->代理对象->实现了数据缓存逻辑
 *
 * 第9讲-高级进阶-ViewState设计-LCE设计-Fragment设计中->目标对象
 * Created by thinkpad on 2018/8/9.
 */
public class FragmentMvpViewStateDelegateImpl<V extends MvpView, P extends MvpPresenter<V>, VS extends ViewState<V>> implements FragmentMvpDelegate<V, P> {

	//解决问题：横竖屏切换
	private Fragment fragment;
	private MvpViewStateDelegateCallback<V, P, VS> delegateCallback;
	//当屏幕方向(横竖屏切换)变化的时候是否缓存Presenter实例
	protected final boolean keepPresenterInstanceDuringScreenOrientationChanges;
	//当返回的时候是否缓存Presenter实例
	protected final boolean keepPresenterOnBackstack;
	protected static final String KEY_VIEW_ID = "com.tz.dream.architect.mvp.framework.id";
	private String viewId;

	//是否使用视图状态
	protected boolean applyViewState = false;
	//是否从内存中使用视图状态
	protected boolean applyViewStateFromMemory = false;
	//是否创建视图回调
	private boolean onViewCreatedCalled = false;

	/**
	 * 1、初始化参数
	 *
	 * @param fragment
	 * @param delegateCallback
	 * @param keepPresenterInstanceDuringScreenOrientationChanges
	 * @param keepPresenterOnBackstack
	 */
	public FragmentMvpViewStateDelegateImpl(Fragment fragment,
											MvpViewStateDelegateCallback<V, P, VS> delegateCallback,
											boolean keepPresenterInstanceDuringScreenOrientationChanges,
											boolean keepPresenterOnBackstack) {
		if (fragment == null) {
			throw new NullPointerException("fragment not null");
		}
		if (delegateCallback == null) {
			throw new NullPointerException("delegateCallback not null");
		}
		if (!keepPresenterInstanceDuringScreenOrientationChanges && keepPresenterOnBackstack) {
			//有一个冲突问题
			//keepPresenterInstanceDuringScreenOrientationChanges == false: 当横竖屏切换我不缓存Presenter
			//keepPresenterOnBackstack == true:表示按下返回键，缓存Presenter
			throw new IllegalArgumentException("参数异常...");
		}
		this.fragment = fragment;
		this.delegateCallback = delegateCallback;
		this.keepPresenterInstanceDuringScreenOrientationChanges = keepPresenterInstanceDuringScreenOrientationChanges;
		this.keepPresenterOnBackstack = keepPresenterOnBackstack;
	}

	/**
	 * 2、通过生命周期方法->控制View状态和数据缓存（恢复）
	 *
	 * @param context
	 */
	@Override
	public void onAttach(Context context) {

	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		//当Activity创建的时候
		if (savedInstanceState != null && keepPresenterInstanceDuringScreenOrientationChanges) {
			//缓存->读取数据->恢复
			//缓存：P层（Presenter）和V层（数据->Bundle）
			viewId = savedInstanceState.getString(KEY_VIEW_ID);
			//读取缓存P层->恢复
			P presenter = restorePresenterOrRecreateNewPresenterAfterProcessDeath();
			delegateCallback.setPresenter(presenter);
			//读取缓存V层（数据）
			VS viewState = restoreViewStateOrRecreateViewStateAfterProcessDeath(savedInstanceState);
			delegateCallback.setViewState(viewState);
		} else {
			//重新创建
			P presenter = createViewIdAndPresenter();
			delegateCallback.setPresenter(presenter);
			VS viewState = createViewState();
			delegateCallback.setViewState(viewState);
		}
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {

	}

	@Override
	public void onViewCreated(View view, Bundle savedInstanceState) {
		onViewCreatedCalled = true;
	}

	@Override
	public void onStart() {
		if (!onViewCreatedCalled) {
			throw new IllegalArgumentException("必须要进行回调...");
		}
		//MVP回调是有顺序的
		if (applyViewState) {
			//是否显示这个视图
			VS viewState = delegateCallback.getViewState();
			V mvpView = delegateCallback.getMvpView();
			if (viewState == null) {
				throw new NullPointerException("ViewState not null");
			}
			//恢复
			delegateCallback.setRestoringViewState(true);
			viewState.apply(mvpView, applyViewStateFromMemory);
			delegateCallback.setRestoringViewState(false);
		}
		//绑定V层
		delegateCallback.getPresenter().attachView(delegateCallback.getMvpView());
		if (applyViewState) {
			if (!applyViewStateFromMemory && keepPresenterInstanceDuringScreenOrientationChanges) {
				//applyViewStateFromMemory
				//false:表示缓存中不存在数据
				//keepPresenterInstanceDuringScreenOrientationChanges
				//true:表示横竖屏切换需要缓存
				//说白了：内存中不存在缓存数据，这个时候我们需要缓存新的数据
				if (viewId == null) {
					throw new IllegalArgumentException("ViewId not null...");
				}
				PresenterManager.putViewState(getActivity(), viewId, delegateCallback.getViewState());
			}
			delegateCallback.onViewStateInstanceRestored(applyViewStateFromMemory);
		} else {
			delegateCallback.onNewViewStateInstance();
		}
	}

	@Override
	public void onPause() {

	}

	@Override
	public void onResume() {

	}

	@Override
	public void onStop() {
		delegateCallback.getPresenter().detachView();
		if (keepPresenterInstanceDuringScreenOrientationChanges) {
			applyViewState = true;
			applyViewStateFromMemory = true;
		} else {
			applyViewState = false;
			applyViewStateFromMemory = false;
		}
	}

	@Override
	public void onDestroyView() {
		onViewCreatedCalled = false;
	}

	@Override
	public void onDestroy() {
		Activity activity = getActivity();
		boolean rerainPresenterInstance = FragmentMvpDelegateImpl.retainPresenterInstance(activity, fragment, keepPresenterInstanceDuringScreenOrientationChanges, keepPresenterOnBackstack);
		P presenter = delegateCallback.getPresenter();
		//是否保留数据
		if (!rerainPresenterInstance) {
			//false:表示需要销毁，不再使用了
			presenter.destroy();
		}
		//清空缓存
		if (!rerainPresenterInstance && viewId != null) {
			PresenterManager.remove(activity, viewId);
		}
	}

	@Override
	public void onSaveInstanceState(Bundle outState) {
		if ((keepPresenterInstanceDuringScreenOrientationChanges || keepPresenterOnBackstack) && outState != null) {
			//缓存
			outState.putString(KEY_VIEW_ID, viewId);
		}
		boolean retainPresenterInstance = FragmentMvpDelegateImpl.retainPresenterInstance(getActivity(), fragment, keepPresenterInstanceDuringScreenOrientationChanges, keepPresenterOnBackstack);
		VS viewStae = delegateCallback.getViewState();
		if (viewStae == null) {
			throw new NullPointerException("view state not null...");
		}
		if (retainPresenterInstance && viewStae instanceof RestorableViewState) {
			//保存到->序列号保存
			//通过数据库...
			((RestorableViewState) viewStae).onSaveInstanceState(outState);
		}
	}

	@Override
	public void onDetach() {

	}

	private Activity getActivity() {
		Activity activity = fragment.getActivity();
		if (activity == null) {
			throw new NullPointerException(
					"Activity returned by Fragment.getActivity() is null. Fragment is " + fragment);
		}
		return activity;
	}

	/**
	 * 恢复Presenter或者在进程死亡之后重新创建Presenter
	 *
	 * @return
	 */
	private P restorePresenterOrRecreateNewPresenterAfterProcessDeath() {
		P presenter;
		if (keepPresenterInstanceDuringScreenOrientationChanges) {
			if (viewId != null
					&& (presenter = PresenterManager.getPresenter(getActivity(), viewId)) != null) {
				return presenter;
			}
		}
		presenter = createViewIdAndPresenter();
		return presenter;
	}

	/**
	 * 创建viewId和presenter
	 *
	 * @return
	 */
	private P createViewIdAndPresenter() {
		P presenter = delegateCallback.createPresenter();
		if (presenter == null) {
			throw new NullPointerException(
					"Presenter returned from createPresenter() is null. Fragment is " + fragment);
		}

		if (keepPresenterInstanceDuringScreenOrientationChanges) {
			viewId = UUID.randomUUID().toString();
			PresenterManager.putPresenter(getActivity(), viewId, presenter);
		}
		return presenter;
	}

	private VS restoreViewStateOrRecreateViewStateAfterProcessDeath(Bundle bundle) {

		if (bundle == null) {
			throw new NullPointerException("Bundle is null. This should never be the case"
					+ "Please report this issue at https://github.com/sockeqwe/mosby/issues");
		}

		if (viewId == null) {
			throw new NullPointerException(
					"The (internal) Mosby View id is null although bundle is not null. "
							+ "This should never be the case while restoring ViewState instance. "
							+ "Please report this issue at https://github.com/sockeqwe/mosby/issues");
		}

		VS viewState = PresenterManager.getViewState(fragment.getActivity(), viewId);
		if (viewState != null) {
			applyViewState = true;
			applyViewStateFromMemory = true;
			return viewState;
		}

		viewState = delegateCallback.createViewState();
		if (viewState == null) {
			throw new NullPointerException(
					"ViewState returned from createViewState() is null! MvpView that has returned null as ViewState is: "
							+ delegateCallback.getMvpView());
		}

		if (viewState instanceof RestorableViewState) {
			// A little bit hacky that we need an instance of the viewstate to restore a view state
			// (may creates another view state object) but I don't know any better way :)
			RestorableViewState restoredViewState =
					((RestorableViewState) viewState).onRestoreInstanceState(bundle);

			if (restoredViewState != null) {
				//
				// ViewState restored from bundle
				//
				viewState = (VS) restoredViewState;
				applyViewState = true;
				applyViewStateFromMemory = false;

				if (keepPresenterInstanceDuringScreenOrientationChanges) {
					PresenterManager.putViewState(getActivity(), viewId, viewState);
				}
				return viewState;
			}
		}

		//
		// Entirely new ViewState has been created, typically because process death and mosby view id points to
		// a  old id but view got a new one because of process death.
		//

		applyViewState = false;
		applyViewStateFromMemory = false;

		if (keepPresenterInstanceDuringScreenOrientationChanges) {
			PresenterManager.putViewState(getActivity(), viewId, viewState);
		}
		return viewState;
	}

	/**
	 * 创建ViewState
	 *
	 * @return
	 */
	private VS createViewState() {
		VS viewState = delegateCallback.createViewState();
		if (viewState == null) {
			throw new NullPointerException(
					"ViewState returned from createViewState() is null. Fragment is " + fragment);
		}

		if (keepPresenterInstanceDuringScreenOrientationChanges) {
			PresenterManager.putViewState(getActivity(), viewId, viewState);
		}

		return viewState;
	}

}
























































